package com.zzzy.cont.service.processcon;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zzzy.common.enums.YesOrNoEnum;
import com.zzzy.common.exception.WarningException;
import com.zzzy.common.util.AssertUtil;
import com.zzzy.common.vo.PageResult;
import com.zzzy.common.vo.SortingField;
import com.zzzy.cont.common.enums.ConFileHistoryEditionEnum;
import com.zzzy.cont.common.enums.ConOperateEnum;
import com.zzzy.cont.common.enums.ConStatusEnum;
import com.zzzy.framework.common.util.PageOfficeUtil;
import com.zzzy.cont.dao.entity.ConFileHistory;
import com.zzzy.cont.dao.entity.ConUserOperateLink;
import com.zzzy.cont.dao.entity.Contract;
import com.zzzy.cont.service.ConFileHistoryService;
import com.zzzy.cont.service.ConNotifyMessageService;
import com.zzzy.cont.service.ConService;
import com.zzzy.cont.service.ConUserOperateLinkService;
import com.zzzy.cont.vo.contract.my.ConInfoRes;
import com.zzzy.cont.vo.contract.process.ProcessConButtonRes;
import com.zzzy.cont.vo.contract.process.ProcessConPageReq;
import com.zzzy.cont.vo.contract.process.ProcessConStatisticsRes;
import com.zzzy.cont.vo.pageoffice.OpenOfficeFileRes;
import com.zzzy.framework.common.util.SecurityUtils;
import com.zzzy.framework.common.util.SortFieldUtil;
import com.zzzy.framework.core.mybatis.query.LambdaQueryWrapperE;
import com.zzzy.framework.core.mybatis.query.MPJLambdaWrapperE;
import com.zzzy.framework.dto.LoginUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Objects;
import java.util.Set;

@Service
public class ProcessConService extends ConService {

    @Resource
    private ConUserOperateLinkService conUserOperateLinkService;
    @Resource
    private ConFileHistoryService conFileHistoryService;
    @Resource
    protected ConNotifyMessageService conNotifyMessageService;

    public ProcessConButtonRes getProcessingButton(Long id) {
        validateAuthForQuery(id);
        ConInfoRes conInfo = getConInfo(id);
        LoginUser loginUser = SecurityUtils.getLoginUser();
        ProcessConButtonRes buttonRes = new ProcessConButtonRes();
        //是否当前可操作人
        boolean isCurrentOperator = conInfo.getOperatorId().equals(loginUser.getId());
        boolean isAudit = ConStatusEnum.AUDIT.getValue().equals(conInfo.getStatus());
        boolean isSign = ConStatusEnum.SIGN.getValue().equals(conInfo.getStatus());
        boolean isFulfill = ConStatusEnum.FULFILL.getValue().equals(conInfo.getStatus());
        boolean isArchiving = ConStatusEnum.ARCHIVING.getValue().equals(conInfo.getStatus());
        boolean hasAudit = loginUser.hasControllerPermission(ConOperateEnum.AUDIT.name().toLowerCase());
        boolean hasSign = loginUser.hasControllerPermission(ConOperateEnum.SIGN.name().toLowerCase());
        boolean hasFulfill = loginUser.hasControllerPermission(ConOperateEnum.FULFILL.name().toLowerCase());
        boolean hasArchive = loginUser.hasControllerPermission(ConOperateEnum.ARCHIVE.name().toLowerCase());
        buttonRes.setEditFile(isCurrentOperator && ((isAudit && hasAudit) || (isSign && hasSign)));
        buttonRes.setAudit(isCurrentOperator && isAudit && hasAudit);
        buttonRes.setSign(isCurrentOperator && isSign && hasSign);
        buttonRes.setFulfill(isCurrentOperator && isFulfill && hasFulfill);
        buttonRes.setArchive(isCurrentOperator && isArchiving && hasArchive);
        buttonRes.setBack(isCurrentOperator);
        buttonRes.setCompareClick(isCurrentOperator && isSign && Objects.nonNull(conInfo.getWordFileBlob()) && YesOrNoEnum.NO.getValue().equals(conInfo.getIsFixedFormat()));
        return buttonRes;
    }

    /**
     * 办理中合同列表
     */
    public PageResult<Contract> getProcessingConPage(ProcessConPageReq queryReq) {
        LambdaQueryWrapperE<Contract> queryWrapperE = new LambdaQueryWrapperE<>();

        Long userId = SecurityUtils.getLoginUser().getId();
        queryWrapperE.eq(Contract::getOperatorId, userId)
                .neIfPresent(Contract::getUserId, userId)
                .likeIfPresent(Contract::getName, queryReq.getName())
                .likeIfPresent(Contract::getConNo, queryReq.getConNo())
                .likeIfPresent(Contract::getOrderNo, queryReq.getOrderNo())
                .likeIfPresent(Contract::getTradeType, queryReq.getTradeType())
                .likeIfPresent(Contract::getConType, queryReq.getConType())
                .likeIfPresent(Contract::getTradeCompany, queryReq.getTradeCompany())
                .likeIfPresent(Contract::getHasPeriod, queryReq.getHasPeriod())
                .eqIfPresent(Contract::getStatus, queryReq.getStatus())
                .eqIfPresent(Contract::getUserName, queryReq.getUserName())
                .betweenIfPresent(Contract::getUpdateTime, queryReq.getBeginUpdateTime()
                        , Objects.nonNull(queryReq.getEndUpdateTime()) ? queryReq.getEndUpdateTime().plusDays(1) : null)
                .orderByDesc(Contract::getUpdateTime);

        Set<SortingField> sortingFieldSet = SortFieldUtil.getSortingFields(Contract.class, queryReq.getOrderField(), queryReq.getOrderRule());
        return baseMapper.selectPage(queryReq, sortingFieldSet, queryWrapperE);
    }
    @Transactional
    public void updateWord(Long id, byte[] byteArray, Integer revisionCount) {
        AssertUtil.isTrue(getProcessingButton(id).isEditFile(), "用户当前无法修改此合同");
        conFileService.updateWordByConId(id, byteArray, revisionCount);

        Contract contract = getConById(id);
        contract.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(contract);
    }

    @Transactional
    public void updatePdf(Long id, byte[] byteArray) {
        AssertUtil.isTrue(getProcessingButton(id).isEditFile(), "用户当前无法修改此合同");
        conFileService.updatePdfByConId(id, byteArray);

        Contract contract = getConById(id);
        contract.setUpdateTime(LocalDateTime.now());
        baseMapper.updateById(contract);
        //添加签订中备份版本备份
        conFileHistoryService.addSigningHistory(id);
    }

    @Transactional
    public void back(Long id) {
        Contract contract = getConByIdForOperate(id);
        String message = contract.getTradeCompany() +" - "+ contract.getName() + " 已被退回";
        conNotifyMessageService.addNotifyMessage(id, contract.getUserId(), message);

        operateConByConId(id);
        conActivityNoteService.addSysNote(id, "退回合同");
    }

    @Transactional
    public void audit(Long id) {
        Contract contract = getConByIdForOperate(id);
        String message = contract.getTradeCompany() +" - "+ contract.getName() + " 已审核通过";
        conNotifyMessageService.addNotifyMessage(id, contract.getUserId(), message);

        operateConByConId(id);
        conActivityNoteService.addSysNote(id, "审核通过");
    }

    @Transactional
    public void sign(Long id) {
        Contract contract = getConByIdForOperate(id);
        String message = contract.getTradeCompany() +" - "+ contract.getName() + " 已签订";
        conNotifyMessageService.addNotifyMessage(id, contract.getUserId(), message);

        operateConByConId(id);
        conActivityNoteService.addSysNote(id, "已签订");
    }

    @Transactional
    public void fulfill(Long id) {
        Contract contract = getConByIdForOperate(id);
        String message = contract.getTradeCompany() +" - "+ contract.getName() + " 已同意履行完毕";
        conNotifyMessageService.addNotifyMessage(id, contract.getUserId(), message);

        operateConByConId(id);
        conActivityNoteService.addSysNote(id, "同意履行完毕");
    }

    @Transactional
    public void archive(Long id) {
        Contract contract = getConByIdForOperate(id);
        String message = contract.getTradeCompany() +" - "+ contract.getName() + " 已同意归档";
        conNotifyMessageService.addNotifyMessage(id, contract.getUserId(), message);

        operateConByConId(id);
        conActivityNoteService.addSysNote(id, "同意归档");
    }

    private void operateConByConId(Long id) {
        Contract contract = getConByIdForOperate(id);
        contract.setUpdateTime(LocalDateTime.now());
        contract.setOperatorId(contract.getUserId());
        contract.setOperatorName(contract.getUserName());
        baseMapper.updateById(contract);

        conUserOperateLinkService.addByConId(id);
    }

    /**
     * 已办理合同列表
     */
    public PageResult<Contract> getProcessedConPage(ProcessConPageReq queryReq) {
        MPJLambdaWrapperE<Contract> queryWrapperE = new MPJLambdaWrapperE<>();
        Long userId = SecurityUtils.getLoginUser().getId();
        queryWrapperE.innerJoin(ConUserOperateLink.class, ConUserOperateLink::getConId, Contract::getId)
                .eq(ConUserOperateLink::getUserId, userId);
        queryWrapperE.likeIfPresent(Contract::getName, queryReq.getName())
                .likeIfPresent(Contract::getConNo, queryReq.getConNo())
                .likeIfPresent(Contract::getOrderNo, queryReq.getOrderNo())
                .likeIfPresent(Contract::getTradeType, queryReq.getTradeType())
                .likeIfPresent(Contract::getConType, queryReq.getConType())
                .likeIfPresent(Contract::getTradeCompany, queryReq.getTradeCompany())
                .likeIfPresent(Contract::getHasPeriod, queryReq.getHasPeriod())
                .eqIfPresent(Contract::getStatus, queryReq.getStatus())
                .neIfPresent(Contract::getOperatorId, userId)
                .likeIfPresent(Contract::getUserName, queryReq.getUserName())
                .betweenIfPresent(Contract::getUpdateTime, queryReq.getBeginUpdateTime(), Objects.nonNull(queryReq.getEndUpdateTime()) ? queryReq.getEndUpdateTime().plusDays(1) : null)
                .orderByDesc(Contract::getUpdateTime);

        Set<SortingField> sortingFieldSet = SortFieldUtil.getSortingFields(Contract.class, queryReq.getOrderField(), queryReq.getOrderRule());
        return baseMapper.selectPage(queryReq, sortingFieldSet, queryWrapperE);
    }

    /**
     * 获取初始版本，审核完毕版本 对比
     */
    public OpenOfficeFileRes getComparePageOfficeResByConId(Long id, String openFileUrl) {
        ConInfoRes conInfo = getConInfo(id);
        if (Objects.isNull(conInfo.getWordFileBlob())) {
            throw new WarningException("当前文件是起草人手动上传的PDF格式文件，无法查看变动");
        }
        if (YesOrNoEnum.YES.getValue().equals(conInfo.getIsFixedFormat())) {
            throw new WarningException("当前文件是固定格式文件，无法查看变动");
        }
        ConFileHistory initialFileHistory = conFileHistoryService.getConFileHistoryByConIdAndEdition(id, ConFileHistoryEditionEnum.INITIAL);
        ConFileHistory auditedFileHistory = conFileHistoryService.getConFileHistoryByConIdAndEdition(id, ConFileHistoryEditionEnum.AUDITED);
        String templateName = StringUtils.isNotBlank(conInfo.getFileTemplateName()) ? conInfo.getFileTemplateName() : "未选模板";
        String caption = conInfo.getName() + " 【模板："+ templateName +"】【固定格式："+ conInfo.getIsFixedFormat() +"】";
        String compareWordHtml = PageOfficeUtil.getCompareWordHtml(openFileUrl + initialFileHistory.getId()
                , openFileUrl + auditedFileHistory.getId(), caption);
        return OpenOfficeFileRes.builder().html(compareWordHtml).build();
    }

    public ProcessConStatisticsRes getStatistics() {
        Long userId = SecurityUtils.getLoginUser().getId();
        long processedCount = baseMapper.selectProcessedCount(userId);
        Long processing = baseMapper.selectCount(new LambdaQueryWrapper<Contract>().eq(Contract::getOperatorId, userId).ne(Contract::getUserId, userId));
        ProcessConStatisticsRes statisticsRes = new ProcessConStatisticsRes();
        statisticsRes.setProcessingCount(processing);
        statisticsRes.setProcessedCount(processedCount);
        return statisticsRes;
    }
}
